<template>
  <div class="validate-input mb-10">
    <slot></slot>
    <div class="mt-1 mb-3">
      <input
        v-if="tag === 'input'"
        :class="{ 'is-invalid': inputRef.error }"
        class="form-control"
        :value="inputRef.val"
        :placeholder="placeholder"
        :type="type"
        @input="updateValue"
        @blur="validateInput"
      />
      <select
        v-else-if="tag === 'select' && options"
        :value="inputRef.val"
        @input="updateValue"
        class="form-control"
        :style="{ color: inputRef.val ? '' : 'rgb(104 111 119)' }"
        autocomplete="off"
      >
        <option selected disabled value="">{{ placeholder }}</option>
        <option v-for="opt in options" :value="opt.value" :key="opt.value">
          {{ opt.label }}
        </option>
      </select>
      <textarea
        v-else
        class="textarea form-control"
        cols="30"
        rows="10"
        :class="{ 'is-invalid': inputRef.error }"
        :placeholder="placeholder"
        :value="inputRef.val"
        @input="updateValue"
      >
      </textarea>
    </div>
    <p class="invalid-feedback" :style="{ display: inputRef.error ? 'block' : 'none' }">{{ inputRef.message }}</p>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, PropType, reactive, computed } from 'vue';
import { emitter } from './ValidateForm.vue';
interface ruleProp {
  type: 'required' | 'email' | 'range' | 'custom';
  message: string;
  validate?: (val: string) => boolean;
}
// const emailReg = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
export type ruleProps = ruleProp[];
export type optionsProps = {
  label: string;
  value: string;
};
export type inputType = 'text' | 'password' | 'file' | 'image' | 'textarea' | 'checkbox';
export type tagType = 'input' | 'select' | 'textarea';
export default defineComponent({
  name: 'validateInput',
  props: {
    rules: Array as PropType<ruleProps>,
    modelValue: String,
    tag: {
      type: String as PropType<tagType>,
      default: 'input'
    },
    type: {
      type: String as PropType<inputType>,
      default: 'text'
    },
    placeholder: {
      type: String,
      default: '请输入内容'
    },
    options: {
      type: Array as PropType<optionsProps[]>
    }
  },
  inheritAttrs: false,
  setup(props, context) {
    const inputRef = reactive({
      // val: props.modelValue || '',
      val: computed({
        get: () => props.modelValue || '',
        set: setVal => {
          context.emit('update:modelValue', setVal);
        }
      }),
      error: false,
      message: ''
    });
    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value;
      inputRef.val = targetValue;
      context.emit('update:modelValue', targetValue);
    };
    const clearValue = () => {
      inputRef.val = '';
      context.emit('update:modelValue', '');
    };
    const validateInput = () => {
      //   console.log('validateInput', props.rules);
      if (props.rules) {
        const allPassed = props.rules.every(rule => {
          let passed: boolean | undefined = true;
          inputRef.message = rule.message;
          switch (rule.type) {
            case 'required':
              passed = inputRef.val.trim() !== '';
              break;
            case 'email':
            case 'range':
            case 'custom':
              passed = rule.validate && rule.validate(inputRef.val);
              break;
            default:
              break;
          }
          return passed;
        });
        inputRef.error = !allPassed;
        return allPassed;
      }
      return true;
    };
    onMounted(() => {
      emitter.emit('form-item-created', validateInput);
      emitter.emit('form-clear-data', clearValue);
    });
    return { inputRef, validateInput, updateValue };
  }
});
</script>

<style></style>
